home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 March / PCWorld_2007-03_cd.bin / domacnost a kancelar / scribus / scribus-1.3.3.7-win32-install.exe / tcl / tcl8.4 / msgcat1.3 / msgcat.tcl next >
Text File  |  2004-04-07  |  13KB  |  468 lines

  1. # msgcat.tcl --
  2. #
  3. #    This file defines various procedures which implement a
  4. #    message catalog facility for Tcl programs.  It should be
  5. #    loaded with the command "package require msgcat".
  6. #
  7. # Copyright (c) 1998-2000 by Ajuba Solutions.
  8. # Copyright (c) 1998 by Mark Harrison.
  9. #
  10. # See the file "license.terms" for information on usage and redistribution
  11. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12. # RCS: @(#) $Id: msgcat.tcl,v 1.17.2.3 2004/03/31 18:51:01 dgp Exp $
  13.  
  14. package require Tcl 8.2
  15. # When the version number changes, be sure to update the pkgIndex.tcl file,
  16. # and the installation directory in the Makefiles.
  17. package provide msgcat 1.3.2
  18.  
  19. namespace eval msgcat {
  20.     namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
  21.         mcunknown
  22.  
  23.     # Records the current locale as passed to mclocale
  24.     variable Locale ""
  25.  
  26.     # Records the list of locales to search
  27.     variable Loclist {}
  28.  
  29.     # Records the mapping between source strings and translated strings.  The
  30.     # array key is of the form "<locale>,<namespace>,<src>" and the value is
  31.     # the translated string.
  32.     array set Msgs {}
  33.  
  34.     # Map of language codes used in Windows registry to those of ISO-639
  35.     array set WinRegToISO639 {
  36.         01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ
  37.               1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY
  38.               2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH
  39.               4001 ar_QA
  40.         02 bg 0402 bg_BG
  41.         03 ca 0403 ca_ES
  42.         04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO
  43.         05 cs 0405 cs_CZ
  44.         06 da 0406 da_DK
  45.         07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI
  46.         08 el 0408 el_GR
  47.         09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ
  48.               1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ
  49.               2c09 en_TT 3009 en_ZW 3409 en_PH
  50.         0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR
  51.               180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE
  52.               2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY
  53.               400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR
  54.         0b fi 040b fi_FI
  55.         0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU
  56.               180c fr_MC
  57.         0d he 040d he_IL
  58.         0e hu 040e hu_HU
  59.         0f is 040f is_IS
  60.         10 it 0410 it_IT 0810 it_CH
  61.         11 ja 0411 ja_JP
  62.         12 ko 0412 ko_KR
  63.         13 nl 0413 nl_NL 0813 nl_BE
  64.         14 no 0414 no_NO 0814 nn_NO
  65.         15 pl 0415 pl_PL
  66.         16 pt 0416 pt_BR 0816 pt_PT
  67.         17 rm 0417 rm_CH
  68.         18 ro 0418 ro_RO
  69.         19 ru
  70.         1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic
  71.         1b sk 041b sk_SK
  72.         1c sq 041c sq_AL
  73.         1d sv 041d sv_SE 081d sv_FI
  74.         1e th 041e th_TH
  75.         1f tr 041f tr_TR
  76.         20 ur 0420 ur_PK 0820 ur_IN
  77.         21 id 0421 id_ID
  78.         22 uk 0422 uk_UA
  79.         23 be 0423 be_BY
  80.         24 sl 0424 sl_SI
  81.         25 et 0425 et_EE
  82.         26 lv 0426 lv_LV
  83.         27 lt 0427 lt_LT
  84.         28 tg 0428 tg_TJ
  85.         29 fa 0429 fa_IR
  86.         2a vi 042a vi_VN
  87.         2b hy 042b hy_AM
  88.         2c az 042c az_AZ@latin 082c az_AZ@cyrillic
  89.         2d eu
  90.         2e wen 042e wen_DE
  91.         2f mk 042f mk_MK
  92.         30 bnt 0430 bnt_TZ
  93.         31 ts 0431 ts_ZA
  94.         33 ven 0433 ven_ZA
  95.         34 xh 0434 xh_ZA
  96.         35 zu 0435 zu_ZA
  97.         36 af 0436 af_ZA
  98.         37 ka 0437 ka_GE
  99.         38 fo 0438 fo_FO
  100.         39 hi 0439 hi_IN
  101.         3a mt 043a mt_MT
  102.         3b se 043b se_NO
  103.         043c gd_UK 083c ga_IE
  104.         3d yi 043d yi_IL
  105.         3e ms 043e ms_MY 083e ms_BN
  106.         3f kk 043f kk_KZ
  107.         40 ky 0440 ky_KG
  108.         41 sw 0441 sw_KE
  109.         42 tk 0442 tk_TM
  110.         43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic
  111.         44 tt 0444 tt_RU
  112.         45 bn 0445 bn_IN
  113.         46 pa 0446 pa_IN
  114.         47 gu 0447 gu_IN
  115.         48 or 0448 or_IN
  116.         49 ta
  117.         4a te 044a te_IN
  118.         4b kn 044b kn_IN
  119.         4c ml 044c ml_IN
  120.         4d as 044d as_IN
  121.         4e mr 044e mr_IN
  122.         4f sa 044f sa_IN
  123.         50 mn
  124.         51 bo 0451 bo_CN
  125.         52 cy 0452 cy_GB
  126.         53 km 0453 km_KH
  127.         54 lo 0454 lo_LA
  128.         55 my 0455 my_MM
  129.         56 gl 0456 gl_ES
  130.         57 kok 0457 kok_IN
  131.         58 mni 0458 mni_IN
  132.         59 sd
  133.         5a syr 045a syr_TR
  134.         5b si 045b si_LK
  135.         5c chr 045c chr_US
  136.         5d iu 045d iu_CA
  137.         5e am 045e am_ET
  138.         5f ber 045f ber_MA
  139.         60 ks 0460 ks_PK 0860 ks_IN
  140.         61 ne 0461 ne_NP 0861 ne_IN
  141.         62 fy 0462 fy_NL
  142.         63 ps
  143.         64 tl 0464 tl_PH
  144.         65 div 0465 div_MV
  145.         66 bin 0466 bin_NG
  146.         67 ful 0467 ful_NG
  147.         68 ha 0468 ha_NG
  148.         69 nic 0469 nic_NG
  149.         6a yo 046a yo_NG
  150.         70 ibo 0470 ibo_NG
  151.         71 kau 0471 kau_NG
  152.         72 om 0472 om_ET
  153.         73 ti 0473 ti_ET
  154.         74 gn 0474 gn_PY
  155.         75 cpe 0475 cpe_US
  156.         76 la 0476 la_VA
  157.         77 so 0477 so_SO
  158.         78 sit 0478 sit_CN
  159.         79 pap 0479 pap_AN
  160.     }
  161. }
  162.  
  163. # msgcat::mc --
  164. #
  165. #    Find the translation for the given string based on the current
  166. #    locale setting. Check the local namespace first, then look in each
  167. #    parent namespace until the source is found.  If additional args are
  168. #    specified, use the format command to work them into the traslated
  169. #    string.
  170. #
  171. # Arguments:
  172. #    src    The string to translate.
  173. #    args    Args to pass to the format command
  174. #
  175. # Results:
  176. #    Returns the translatd string.  Propagates errors thrown by the 
  177. #    format command.
  178.  
  179. proc msgcat::mc {src args} {
  180.     # Check for the src in each namespace starting from the local and
  181.     # ending in the global.
  182.  
  183.     variable Msgs
  184.     variable Loclist
  185.     variable Locale
  186.  
  187.     set ns [uplevel 1 [list ::namespace current]]
  188.     
  189.     while {$ns != ""} {
  190.     foreach loc $Loclist {
  191.         if {[info exists Msgs($loc,$ns,$src)]} {
  192.         if {[llength $args] == 0} {
  193.             return $Msgs($loc,$ns,$src)
  194.         } else {
  195.             return [uplevel 1 \
  196.                 [linsert $args 0 ::format $Msgs($loc,$ns,$src)]]
  197.         }
  198.         }
  199.     }
  200.     set ns [namespace parent $ns]
  201.     }
  202.     # we have not found the translation
  203.     return [uplevel 1 \
  204.         [linsert $args 0 [::namespace origin mcunknown] $Locale $src]]
  205. }
  206.  
  207. # msgcat::mclocale --
  208. #
  209. #    Query or set the current locale.
  210. #
  211. # Arguments:
  212. #    newLocale    (Optional) The new locale string. Locale strings
  213. #            should be composed of one or more sublocale parts
  214. #            separated by underscores (e.g. en_US).
  215. #
  216. # Results:
  217. #    Returns the current locale.
  218.  
  219. proc msgcat::mclocale {args} {
  220.     variable Loclist
  221.     variable Locale
  222.     set len [llength $args]
  223.  
  224.     if {$len > 1} {
  225.     error {wrong # args: should be "mclocale ?newLocale?"}
  226.     }
  227.  
  228.     if {$len == 1} {
  229.     set Locale [string tolower [lindex $args 0]]
  230.     set Loclist {}
  231.     set word ""
  232.     foreach part [split $Locale _] {
  233.         set word [string trimleft "${word}_${part}" _]
  234.         set Loclist [linsert $Loclist 0 $word]
  235.     }
  236.     }
  237.     return $Locale
  238. }
  239.  
  240. # msgcat::mcpreferences --
  241. #
  242. #    Fetch the list of locales used to look up strings, ordered from
  243. #    most preferred to least preferred.
  244. #
  245. # Arguments:
  246. #    None.
  247. #
  248. # Results:
  249. #    Returns an ordered list of the locales preferred by the user.
  250.  
  251. proc msgcat::mcpreferences {} {
  252.     variable Loclist
  253.     return $Loclist
  254. }
  255.  
  256. # msgcat::mcload --
  257. #
  258. #    Attempt to load message catalogs for each locale in the
  259. #    preference list from the specified directory.
  260. #
  261. # Arguments:
  262. #    langdir        The directory to search.
  263. #
  264. # Results:
  265. #    Returns the number of message catalogs that were loaded.
  266.  
  267. proc msgcat::mcload {langdir} {
  268.     set x 0
  269.     foreach p [mcpreferences] {
  270.     set langfile [file join $langdir $p.msg]
  271.     if {[file exists $langfile]} {
  272.         incr x
  273.         set fid [open $langfile "r"]
  274.         fconfigure $fid -encoding utf-8
  275.             uplevel 1 [read $fid]
  276.         close $fid
  277.     }
  278.     }
  279.     return $x
  280. }
  281.  
  282. # msgcat::mcset --
  283. #
  284. #    Set the translation for a given string in a specified locale.
  285. #
  286. # Arguments:
  287. #    locale        The locale to use.
  288. #    src        The source string.
  289. #    dest        (Optional) The translated string.  If omitted,
  290. #            the source string is used.
  291. #
  292. # Results:
  293. #    Returns the new locale.
  294.  
  295. proc msgcat::mcset {locale src {dest ""}} {
  296.     variable Msgs
  297.     if {[llength [info level 0]] == 3} { ;# dest not specified
  298.         set dest $src
  299.     }
  300.  
  301.     set ns [uplevel 1 [list ::namespace current]]
  302.  
  303.     set Msgs([string tolower $locale],$ns,$src) $dest
  304.     return $dest
  305. }
  306.  
  307. # msgcat::mcmset --
  308. #
  309. #    Set the translation for multiple strings in a specified locale.
  310. #
  311. # Arguments:
  312. #    locale        The locale to use.
  313. #    pairs        One or more src/dest pairs (must be even length)
  314. #
  315. # Results:
  316. #    Returns the number of pairs processed
  317.  
  318. proc msgcat::mcmset {locale pairs } {
  319.     variable Msgs
  320.  
  321.     set length [llength $pairs]
  322.     if {$length % 2} {
  323.     error {bad translation list: should be "mcmset locale {src dest ...}"}
  324.     }
  325.     
  326.     set locale [string tolower $locale]
  327.     set ns [uplevel 1 [list ::namespace current]]
  328.     
  329.     foreach {src dest} $pairs {
  330.         set Msgs($locale,$ns,$src) $dest
  331.     }
  332.     
  333.     return $length
  334. }
  335.  
  336. # msgcat::mcunknown --
  337. #
  338. #    This routine is called by msgcat::mc if a translation cannot
  339. #    be found for a string.  This routine is intended to be replaced
  340. #    by an application specific routine for error reporting
  341. #    purposes.  The default behavior is to return the source string.  
  342. #    If additional args are specified, the format command will be used
  343. #    to work them into the traslated string.
  344. #
  345. # Arguments:
  346. #    locale        The current locale.
  347. #    src        The string to be translated.
  348. #    args        Args to pass to the format command
  349. #
  350. # Results:
  351. #    Returns the translated value.
  352.  
  353. proc msgcat::mcunknown {locale src args} {
  354.     if {[llength $args]} {
  355.     return [uplevel 1 [linsert $args 0 ::format $src]]
  356.     } else {
  357.     return $src
  358.     }
  359. }
  360.  
  361. # msgcat::mcmax --
  362. #
  363. #    Calculates the maximun length of the translated strings of the given 
  364. #    list.
  365. #
  366. # Arguments:
  367. #    args    strings to translate.
  368. #
  369. # Results:
  370. #    Returns the length of the longest translated string.
  371.  
  372. proc msgcat::mcmax {args} {
  373.     set max 0
  374.     foreach string $args {
  375.     set translated [uplevel 1 [list [namespace origin mc] $string]]
  376.         set len [string length $translated]
  377.         if {$len>$max} {
  378.             set max $len
  379.         }
  380.     }
  381.     return $max
  382. }
  383.  
  384. # Convert the locale values stored in environment variables to a form
  385. # suitable for passing to [mclocale]
  386. proc msgcat::ConvertLocale {value} {
  387.     # Assume $value is of form: $language[_$territory][.$codeset][@modifier]
  388.     # Convert to form: $language[_$territory][_$modifier]
  389.     #
  390.     # Comment out expanded RE version -- bugs alleged
  391.     # regexp -expanded {
  392.     #    ^        # Match all the way to the beginning
  393.     #    ([^_.@]*)    # Match "lanugage"; ends with _, ., or @
  394.     #    (_([^.@]*))?    # Match (optional) "territory"; starts with _
  395.     #    ([.]([^@]*))?    # Match (optional) "codeset"; starts with .
  396.     #    (@(.*))?    # Match (optional) "modifier"; starts with @
  397.     #    $        # Match all the way to the end
  398.     # } $value -> language _ territory _ codeset _ modifier
  399.     if {![regexp {^([^_.@]+)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \
  400.         -> language _ territory _ codeset _ modifier]} {
  401.     return -code error "invalid locale '$value': empty language part"
  402.     }
  403.     set ret $language
  404.     if {[string length $territory]} {
  405.     append ret _$territory
  406.     }
  407.     if {[string length $modifier]} {
  408.     append ret _$modifier
  409.     }
  410.     return $ret
  411. }
  412.  
  413. # Initialize the default locale
  414. proc msgcat::Init {} {
  415.     #
  416.     # set default locale, try to get from environment
  417.     #
  418.     foreach varName {LC_ALL LC_MESSAGES LANG} {
  419.     if {[info exists ::env($varName)] 
  420.         && ![string equal "" $::env($varName)]} {
  421.         if {![catch {mclocale [ConvertLocale $::env($varName)]}]} {
  422.         return
  423.         }
  424.     }
  425.     }
  426.     #
  427.     # The rest of this routine is special processing for Windows;
  428.     # all other platforms, get out now.
  429.     #
  430.     if { ![string equal $::tcl_platform(platform) windows] } {
  431.     mclocale C
  432.     return
  433.     }
  434.     #
  435.     # On Windows, try to set locale depending on registry settings,
  436.     # or fall back on locale of "C".  
  437.     #
  438.     set key {HKEY_CURRENT_USER\Control Panel\International}
  439.     if {[catch {package require registry}] \
  440.         || [catch {registry get $key "locale"} locale]} {
  441.         mclocale C
  442.     return
  443.     }
  444.     #
  445.     # Keep trying to match against smaller and smaller suffixes
  446.     # of the registry value, since the latter hexadigits appear
  447.     # to determine general language and earlier hexadigits determine
  448.     # more precise information, such as territory.  For example,
  449.     #     0409 - English - United States
  450.     #     0809 - English - United Kingdom
  451.     # Add more translations to the WinRegToISO639 array above.
  452.     #
  453.     variable WinRegToISO639
  454.     set locale [string tolower $locale]
  455.     while {[string length $locale]} {
  456.         if {![catch {mclocale [ConvertLocale $WinRegToISO639($locale)]}]} {
  457.         return
  458.     }
  459.     set locale [string range $locale 1 end]
  460.     }
  461.     #
  462.     # No translation known.  Fall back on "C" locale
  463.     #
  464.     mclocale C
  465. }
  466. msgcat::Init
  467.